#include "door_bell_ws.h"

#define NO_DATA_TIMEOUT_SEC 5
#define CONFIG_WEBSOCKET_URI "ws://192.168.51.38:8000/ws/from_esp"
#define CONFIG_VIDEO_URI "ws://192.168.51.38:8000/ws/image"

static const char *TAG = "websocket";

esp_websocket_client_handle_t audioClient;
RingbufHandle_t ringbuf;
esp_websocket_client_handle_t videoClient;

static void websocket_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
    esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data;
    switch (event_id)
    {
    case WEBSOCKET_EVENT_BEGIN:
        ESP_LOGI(TAG, "WEBSOCKET_EVENT_BEGIN");
        break;
    case WEBSOCKET_EVENT_CONNECTED:
        ESP_LOGI(TAG, "WEBSOCKET_EVENT_CONNECTED");
        break;
    case WEBSOCKET_EVENT_DISCONNECTED:
        ESP_LOGI(TAG, "WEBSOCKET_EVENT_DISCONNECTED");
        break;
    case WEBSOCKET_EVENT_DATA:
        if (data->op_code == 0x2)
        { // Opcode 0x2 indicates binary data
            // ESP_LOG_BUFFER_HEX("Received binary data", data->data_ptr, data->data_len);
            door_bell_sound_Write((uint8_t *)data->data_ptr, data->data_len);
        }

        break;
    case WEBSOCKET_EVENT_ERROR:
        ESP_LOGI(TAG, "WEBSOCKET_EVENT_ERROR");
        break;
    case WEBSOCKET_EVENT_FINISH:
        ESP_LOGI(TAG, "WEBSOCKET_EVENT_FINISH");
        break;
    }
}

void door_bell_ws_Init(void)
{
    esp_websocket_client_config_t websocket_cfg = {};

    websocket_cfg.uri = CONFIG_WEBSOCKET_URI;

    ESP_LOGI(TAG, "Connecting to %s...", websocket_cfg.uri);

    // 初始化传输音频客户端
    audioClient = esp_websocket_client_init(&websocket_cfg);

    // 给传输音频的客户端注册回调函数
    esp_websocket_register_events(audioClient, WEBSOCKET_EVENT_ANY,
                                  websocket_event_handler, (void *)audioClient);

    // 创建环形缓冲区
    ringbuf = xRingbufferCreate(1024 * 8, RINGBUF_TYPE_NOSPLIT);

    // video
    websocket_cfg.uri = CONFIG_VIDEO_URI;

    videoClient = esp_websocket_client_init(&websocket_cfg);
    // ESP不用从前端接收视频数据，只用发送数据到前端，所以不用注册回调函数
}

void door_bell_ws_start(esp_websocket_client_handle_t wsClient)
{
    if (wsClient && esp_websocket_client_is_connected(wsClient) == false)
    {
        MY_LOGI("start ws_client");
        esp_websocket_client_start(wsClient);
    }
}

void door_bell_ws_stop(esp_websocket_client_handle_t wsClient)
{
    if (wsClient && esp_websocket_client_is_connected(wsClient) == true)
    {
        MY_LOGI("stop ws_client");
        esp_websocket_client_close(wsClient, portMAX_DELAY);
    }
}

void esp_buf(void *);
void buf_ws(void *);
TaskHandle_t esp_buf_handle;
TaskHandle_t buf_ws_handle;

uint8_t deleteTask1;
uint8_t deleteTask2;

uint8_t audio_open_count;

void door_bell_ws_audio_open(uint8_t dir)
{
    // MY_LOGI("open client to esp");
    door_bell_ws_start(audioClient);

    audio_open_count++;

    // esp to client
    // 使用环形缓冲区，先将门铃上麦克风的数据存入缓冲区中（任务一），再从缓冲区读取（任务二）
    if (dir == audio_to_master)
    {
        if (esp_buf_handle == NULL)
        {

            xTaskCreate(esp_buf, "client buf", 1024 * 4, NULL, 5, &esp_buf_handle);
        }

        if (buf_ws_handle == NULL)
        {
            xTaskCreate(buf_ws, "buf client", 1024 * 4, NULL, 5, &buf_ws_handle);
        }
    }
}

void door_bell_ws_audio_close(uint8_t dir)
{

    if (audio_open_count)
    {
        audio_open_count--;
    }

    if (audio_open_count == 0)
    {
        MY_LOGI("close audio client ");
        door_bell_ws_stop(audioClient);
    }

    if (dir == audio_to_master)
    {
        deleteTask1 = 1;
        deleteTask2 = 1;
    }
}

// send to websocket
void send_data_to_ws(esp_websocket_client_handle_t wsClient,
                     uint8_t *data,
                     int len)
{
    if (wsClient && esp_websocket_client_is_connected(wsClient) && data && len)
    {
        esp_websocket_client_send_bin(wsClient, (char *)data, len, 5000);
    }
}

void esp_buf(void *)
{
    MY_LOGI("esp to buf task start");
    uint8_t data[512 - 8] = {0};

    while (1)
    {
        // 从门铃的麦克风读取数据
        door_bell_sound_Read(data, sizeof(data));
        // 将数据存入环形缓冲区中
        xRingbufferSend(ringbuf, data, sizeof(data), 5000);

        // delete task
        if (deleteTask1)
        {
            MY_LOGI("delete task 1");
            deleteTask1 = 0;
            esp_buf_handle = NULL;
            vTaskDelete(NULL);
        }
    }
}

void buf_ws(void *)
{
    MY_LOGI("buf to ws task start");
    size_t dataLen = 0;

    while (1)
    {
        uint8_t *data = xRingbufferReceive(ringbuf, &dataLen, 5000);
        if (data)
        {
            // send to websocket
            send_data_to_ws(audioClient, data, dataLen);

            // 归还环形缓冲区
            vRingbufferReturnItem(ringbuf, data);
        }

        // delete task
        if (deleteTask2)
        {
            MY_LOGI("delete task 2");
            deleteTask2 = 0;
            buf_ws_handle = NULL;
            vTaskDelete(NULL);
        }
    }
}

void videoTask(void *);
TaskHandle_t video_task_handle;
void door_bell_ws_video_open(void)
{
    MY_LOGI("打开 门铃 到 客户端 的ws 视频客户端");
    door_bell_ws_start(videoClient);

    if (video_task_handle == NULL)
    {
        xTaskCreate(videoTask, "video task", 4096, NULL, 5, &video_task_handle);
    }
}

uint8_t deleteVideoTask;
void door_bell_ws_video_close(void)
{
    deleteVideoTask = 1;
}

void videoTask(void *)
{
    MY_LOGI("video task start");

    uint8_t *picBuf = NULL;
    size_t picBufLen = 0;

    TickType_t tick = xTaskGetTickCount();

    while (1)
    {
        if (deleteVideoTask)
        {
            MY_LOGI("video task deleted");
            video_task_handle = NULL;
            deleteVideoTask = 0;
            vTaskDelete(NULL);
            door_bell_ws_stop(videoClient);
        }

        door_bell_video_getPic(&picBuf, &picBufLen);
        // MY_LOGI("%s, %d", picBuf, picBufLen);

        if (picBuf && picBufLen)
        {
            send_data_to_ws(videoClient, picBuf, picBufLen);

            door_bell_video_returnPic(); // 归还缓冲区
        }

        // 30ms 读取一次，1s可以读取30帧左右
        vTaskDelayUntil(&tick, 30);
    }
}
